package sg.edu.nus.iss.billing.controller;

import java.util.ArrayList;
import java.util.List;

import sg.edu.nus.iss.billing.constant.ErrorCodeConstants;
import sg.edu.nus.iss.billing.datastore.DBFactory;
import sg.edu.nus.iss.billing.datastore.IDataStore;
import sg.edu.nus.iss.billing.datastore.impl.Selector;
import sg.edu.nus.iss.billing.entity.Account;
import sg.edu.nus.iss.billing.entity.Customer;
import sg.edu.nus.iss.billing.entity.RecordState;
import sg.edu.nus.iss.billing.exception.ControllerException;
import sg.edu.nus.iss.billing.exception.DataStoreException;
import sg.edu.nus.iss.billing.localization.MessageKeyManager;
import sg.edu.nus.iss.billing.util.Util;

public class AccountController {

	private IDataStore dataStorage;

	public AccountController() {
		dataStorage = DBFactory.instance().getSDStore();
	}

	public List<Account> getAllAccounts() throws ControllerException {
		List<Account> accountList = new ArrayList<Account>();
		Selector selector = new Selector();
		selector.eq("active", RecordState.ACTIVE);
		try {
			accountList = dataStorage.loadObjectsBySelector(Account.class,
					selector);
		} catch (DataStoreException e) {
			throw new ControllerException(ErrorCodeConstants.ERROR_DATASTORE,
					MessageKeyManager.getMessage("error.dataStore"));
		}
		return accountList;
	}

	public Account isAccountExist(String accountNumber)
			throws ControllerException {
		List<Account> accountList = null;
		Account accountObj = null;
		Selector selector = new Selector();
		selector.eq("accountNumber", accountNumber.toUpperCase());
		try {
			accountList = dataStorage.loadObjectsBySelector(Account.class,
					selector);
		} catch (DataStoreException e) {
			// e.printStackTrace();
			throw new ControllerException(ErrorCodeConstants.ERROR_DATASTORE,
					MessageKeyManager.getMessage("error.dataStore"));
		}
		if (!Util.isEmpty(accountList)) {
			accountObj = accountList.get(0);
		}
		return accountObj;
	}

	public Customer getCustomerByNRICFromAccount(String nric)
			throws ControllerException {
		List<Customer> customerList = null;
		Customer customerObj = null;
		Selector selector = new Selector();
		selector.eq("NRIC", nric.toUpperCase());
		try {
			customerList = dataStorage.loadObjectsBySelector(Customer.class,
					selector);
		} catch (DataStoreException e) {
			// e.printStackTrace();
			throw new ControllerException(ErrorCodeConstants.ERROR_DATASTORE,
					MessageKeyManager.getMessage("error.dataStore"));
		}
		if (customerList != null && customerList.size() > 0) {
			customerObj = customerList.get(0);
		} else {
			throw new ControllerException(
					ErrorCodeConstants.ERROR_CUSTOMER_NOT_FOUND,
					MessageKeyManager.getMessage("error.customerNotFound"));
		}
		return customerObj;
	}

	public Account getAccountByNRIC(String nric) throws ControllerException {
		List<Account> accountList = null;
		Account accountObj = null;
		Customer customerObj = getCustomerByNRICFromAccount(nric);
		String accountNumber = customerObj.getAccountNumber();
		Selector selector = new Selector();
		selector.eq("accountNumber", accountNumber);
		try {
			accountList = dataStorage.loadObjectsBySelector(Account.class,
					selector);
		} catch (DataStoreException e) {
			// e.printStackTrace();
			throw new ControllerException(ErrorCodeConstants.ERROR_DATASTORE,
					MessageKeyManager.getMessage("error.dataStore"));
		}
		if (accountList != null && accountList.size() > 0) {
			accountObj = accountList.get(0);
		} else {
			throw new ControllerException(
					ErrorCodeConstants.ERROR_ACCOUNT_NOT_FOUND,
					MessageKeyManager.getMessage("error.accountNotFound"));
		}
		return accountObj;
	}

	public Account getAccountByAccountNumber(String accountNumber)
			throws ControllerException {
		List<Account> accountList = null;
		Account accountObj = null;
		Selector selector = new Selector();
		selector.eq("accountNumber", accountNumber);
		try {
			accountList = dataStorage.loadObjectsBySelector(Account.class,
					selector);
		} catch (DataStoreException e) {
			throw new ControllerException(ErrorCodeConstants.ERROR_DATASTORE,
					MessageKeyManager.getMessage("error.dataStore"));
		}
		if (accountList != null && accountList.size() > 0) {
			accountObj = accountList.get(0);
		} else {
			throw new ControllerException(
					ErrorCodeConstants.ERROR_ACCOUNT_NOT_FOUND,
					MessageKeyManager.getMessage("error.accountNotFound"));
		}
		return accountObj;
	}

	public boolean validateAccountID(Account accountObj)
			throws ControllerException {
		String accID = accountObj.getId();
		if (Util.isEmpty(accID)) {
			throw new ControllerException(
					ErrorCodeConstants.ERROR_ACCOUNT_NOT_FOUND,
					MessageKeyManager.getMessage("error.accountNotFound"));
		} else {
			return true;
		}
	}

	public void addAccount(String accountNumber, Customer customerObj)
			throws ControllerException {
		Account accObj = null;
		Account accountObj = null;
		try {
			// set account as active
			accountObj = new Account();
			accountObj.setAccountNumber(accountNumber);
			accountObj.setActive(RecordState.ACTIVE);
			accountObj.setCustomer(customerObj);

			// check if account is exist
			accObj = isAccountExist(accountNumber);
			if (accObj != null) {
				throw new ControllerException(
						ErrorCodeConstants.ERROR_ACCOUNT_DUPLICATION,
						MessageKeyManager
								.getMessage("error.accountDuplication"));
			} else {
				dataStorage.saveObject(accountObj);
			}
		} catch (DataStoreException e) {
			e.printStackTrace();
			throw new ControllerException(ErrorCodeConstants.ERROR_DATASTORE,
					MessageKeyManager.getMessage("error.dataStore"));
		}
	}

	public void deleteAccount(Account accountObj) throws ControllerException {
		if (validateAccountID(accountObj)) {
			try {
				accountObj.setActive(RecordState.DELETED);
				dataStorage.saveObject(accountObj);
			} catch (DataStoreException e) {
				throw new ControllerException(
						ErrorCodeConstants.ERROR_DATASTORE,
						MessageKeyManager.getMessage("error.dataStore"));
			}
		}
	}

	public void restoreAccount(Account accountObj) throws ControllerException {
		if (validateAccountID(accountObj)) {
			try {
				accountObj.setActive(RecordState.ACTIVE);
				dataStorage.saveObject(accountObj);
			} catch (DataStoreException e) {
				throw new ControllerException(
						ErrorCodeConstants.ERROR_DATASTORE,
						MessageKeyManager.getMessage("error.dataStore"));
			}
		}
	}

	public void editAccount(Account accountObj) throws ControllerException {
		if (validateAccountID(accountObj)) {
			try {
				dataStorage.saveObject(accountObj);
			} catch (DataStoreException e) {
				throw new ControllerException(
						ErrorCodeConstants.ERROR_DATASTORE,
						MessageKeyManager.getMessage("error.dataStore"));
			}
		}
	}
}
